import * as THREE from "three";
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
//引入性能监视器stats.js
import Stats from "three/addons/libs/stats.module.js";

const stats = new Stats();

// stats.domElement显示：渲染帧率  刷新频率,一秒渲染次数
// stats.setMode(0);//默认模式
//stats.domElement显示：渲染周期 渲染一帧多长时间(单位：毫秒ms)
stats.setMode(1);

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// ------------------------------------------------
// 管道TubeGeometry几何体的功能就是基于一个3D曲线路径，生成一个管道几何体
// 构造函数格式：TubeGeometry(path, tubularSegments, radius, radiusSegments, closed)
// path	扫描路径，路径要用三维曲线
// tubularSegments	路径方向细分数，默认64
// radius	管道半径，默认1
// radiusSegments	管道圆弧细分数，默认8
// closed	Boolean值，管道是否闭合
// 三维样条曲线
// const path = new THREE.CatmullRomCurve3([
//   new THREE.Vector3(-50, 20, 90),
//   new THREE.Vector3(-10, 40, 40),
//   new THREE.Vector3(0, 0, 0),
//   new THREE.Vector3(60, -60, 0),
//   new THREE.Vector3(70, 0, 80),
// ]);
// // path:路径   40：沿着轨迹细分数  2：管道半径   25：管道截面圆细分数
// const geometry = new THREE.TubeGeometry(path, 40, 2, 25);


// 旋转LatheGeometry案例
// 格式：LatheGeometry(points, segments, phiStart, phiLength)
// points	Vector2表示的坐标数据组成的数组
// segments	圆周方向细分数，默认12
// phiStart	开始角度,默认0
// phiLength	旋转角度，默认2π
// LatheGeometry类第一个参数就是旋转轮廓，旋转轮廓使用多个二维向量Vector2表示的xy坐标去描述
// LatheGeometry的旋转轮廓默认绕y轴旋转生成曲面几何体。

// Vector2表示的三个点坐标，三个点构成的轮廓相当于两端直线相连接
// const pointsArr = [
//   new THREE.Vector2(50, 60), 
//   new THREE.Vector2(25, 0),
//   new THREE.Vector2(50, -60)
// ];
// LatheGeometry：pointsArr轮廓绕y轴旋转生成几何体曲面
// pointsArr：旋转几何体的旋转轮廓形状
// const geometry = new THREE.LatheGeometry(pointsArr, 30);
// const geometry = new THREE.LatheGeometry(pointsArr, 30, 0, 2 * Math.PI);

// 轮廓填充 ShapeGeometry

// 一组二维向量表示一个多边形轮廓坐标
// const pointsArr = [
//   new THREE.Vector2(-50, -50),
//   new THREE.Vector2(-60, 0),
//   new THREE.Vector2(0, 50),
//   new THREE.Vector2(60, 0),
//   new THREE.Vector2(50, -50),
// ]

// const shape = new THREE.Shape(pointsArr);
// const geometry = new THREE.ShapeGeometry(shape);
// const material = new THREE.MeshLambertMaterial({
//   wireframe:true,
// });


// 拉伸ExtrudeGeometry
// Shape表示一个平面多边形轮廓
// const shape = new THREE.Shape([
//   // 按照特定顺序，依次书写多边形顶点坐标
//   new THREE.Vector2(-50, -50), //多边形起点
//   new THREE.Vector2(-50, 50),
//   new THREE.Vector2(50, 50),
//   new THREE.Vector2(50, -50),
// ]);

// const geometry = new THREE.ExtrudeGeometry(
//   shape, //二维轮廓
//   {
//       depth: 20, //拉伸长度
//       bevelThickness: 5, //倒角尺寸:拉伸方向
//       bevelSize: 5, //倒角尺寸:垂直拉伸方向
//       // bevelSegments: 20, //倒圆角：倒角细分精度，默认3
//       bevelSegments: 1, //倒直角
//       bevelEnabled: false, //禁止倒角,默认true
//   }
// );


// 扫描ExtrudeGeometry
// 通过ExtrudeGeometry除了可以实现拉伸成型，也可以让一个平面轮廓Shape沿着曲线扫描成型

const shape = new THREE.Shape([
  // 按照特定顺序，依次书写多边形顶点坐标
  new THREE.Vector2(0,0), //多边形起点
  new THREE.Vector2(0,10),
  new THREE.Vector2(10,10),
  new THREE.Vector2(10,0),
]);

// 扫描轨迹：创建轮廓的扫描轨迹(3D样条曲线)
const curve = new THREE.CatmullRomCurve3([
  new THREE.Vector3( -10, -50, -50 ),
  new THREE.Vector3( 10, 0, 0 ),
  new THREE.Vector3( 8, 50, 50 ),
  new THREE.Vector3( -5, 0, 100)
]);

//扫描造型：扫描默认没有倒角
const geometry = new THREE.ExtrudeGeometry(
  shape, //扫描轮廓
  {
      extrudePath:curve,//扫描轨迹
      steps:1000//沿着路径细分精度，越大越光滑
  }
);


const material = new THREE.MeshLambertMaterial({
  side: THREE.FrontSide, //双面显示看到管道内壁
});
// THREE.FrontSide 仅渲染几何体的正面。这是默认行为，意味着只有当观察者从多边形顶点按照顺时针顺序定义的那一面看过去时，才能看到材质。
// THREE.BackSide ：仅渲染几何体的背面。这意味着只有当观察者从多边形顶点按照逆时针顺序定义的那一面看过去时，才能看到材质
// THREE.DoubleSide ：同时渲染几何体的正面和背面。这对于创建诸如窗户、纸张等双面都可见的对象非常有用。
const line = new THREE.LineSegments(geometry, material);

scene.add(line);
// -----------------------------------------------
// 设置相机的位置以便更好地查看线段
camera.position.z = 200;
camera.position.y = 200;
camera.position.x = 200;
// 渲染循环
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

const axesHelper = new THREE.AxesHelper(150);

// 添加辅助坐标系
scene.add(axesHelper);

// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
// const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度
// const height = window.innerHeight; //窗口文档显示区的高度作为画布高度

//点光源：两个参数分别表示光源颜色和光照强度
const pointLight = new THREE.PointLight(0xffffff, 1.0);
pointLight.decay = 1.0; //设置光源距离衰减

// 你可以对比不同光照强度明暗差异(传播同样距离)
pointLight.intensity = 100.0; //光照强度
// pointLight.intensity = 50000.0;//光照强度

//点光源位置 ,放在x轴上
// pointLight.position.set(0, 400, 400);
// pointLight.position.set(100, 60, 50);
pointLight.position.set(100, 50, 75);

//点光源添加到场景中
// scene.add(pointLight);

// 光源辅助观察
// const pointLightHelper = new THREE.PointLightHelper(pointLight, 10);
// scene.add(pointLightHelper);

//环境光:没有特定方向，整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.1);
scene.add(ambient);

// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向：通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(80, 100, 50);
// directionalLight.position.set(100, 0, 0);
// directionalLight.position.set(0, 100, 0);
// directionalLight.position.set(100, 100, 100);
// directionalLight.position.set(100, 60, 50);
// 方向光指向对象网格模型mesh，可以不设置，默认的位置是0,0,0
// directionalLight.target = mesh;
// scene.add(directionalLight);

// DirectionalLightHelper：可视化平行光
// const dirLightHelper = new THREE.DirectionalLightHelper(
//   directionalLight,
//   5,
//   0xff0000
// );
// scene.add(dirLightHelper);

// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 启用阻尼效果
controls.enableDamping = true;
controls.dampingFactor = 0.05;

// 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
controls.addEventListener("change", function () {
  renderer.render(scene, camera); //执行渲染操作
  // 浏览器控制台查看相机位置变化
  // console.log("camera.position", camera.position);
});

//执行渲染操作
renderer.render(scene, camera);

// Canvas画布插入到任意HTML元素中
// document.getElementById("webgl").appendChild(renderer.domElement);

document.body.appendChild(renderer.domElement);
document.body.appendChild(stats.domElement);

// 渲染函数
function render() {
  renderer.render(scene, camera); //执行渲染操作
  // mesh.rotateY(0.01); //每次绕y轴旋转0.01弧度
  controls.update(); // 必须调用此方法，以便阻尼效果生效
  stats.update(); //requestAnimationFrame循环调用的函数中调用方法update(),来刷新时间
  requestAnimationFrame(render); //请求再次执行渲染函数render，渲染下一帧
}
render();

window.onresize = function () {
  // 重置渲染器输出画布canvas尺寸
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
  // 但是不会每渲染一帧，就通过相机的属性计算投影矩阵(节约计算资源)
  // 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
  camera.updateProjectionMatrix();
};

// console.log(THREE);
